import hashlib
import json
import zipfile
from io import BytesIO
from pathlib import Path
from typing import Any, List

from fastapi import UploadFile, HTTPException

from app.models import File


def load_file_data(data_file: str, data_dri: Path = Path("static")) -> Any:
    # 获取当前文件所在目录
    data_file = data_dri / data_file

    if not data_file.exists():
        raise FileNotFoundError("{0:-^100}".format(f"找不到文件：{data_file}"))

    with open(data_file, "r", encoding="utf-8") as file:
        data = json.load(file)
    return data


def save_file(data: Any, data_file: str, data_dri: Path = Path("static")):
    # 获取当前文件所在目录
    data_file = data_dri / data_file
    with open(data_file, "w", encoding="utf-8") as file:
        json.dump(data, file, ensure_ascii=False, indent=4)


def create_zip(files: List[File], base_dir: Path = Path("static")) -> BytesIO:
    """
    创建ZIP文件
    :param files: 文件列表
    :param base_dir: 基础目录, 默认 static
    """
    zip_buffer = BytesIO()

    with zipfile.ZipFile(zip_buffer, "w", zipfile.ZIP_DEFLATED) as zipf:
        for file in files:
            # 构造安全路径
            file_path = (base_dir / file.url).resolve()

            # 验证路径是否在基础目录内
            try:
                file_path.relative_to(base_dir.resolve())
            except ValueError:
                raise HTTPException(
                    status_code=400, detail=f"文件名称为{file.name}的文件路径无效"
                )

            # 验证所有文件都存在
            if not file_path.is_file():
                raise HTTPException(
                    status_code=404, detail=f"没有找到名称为{file.name}的文件"
                )

            # 添加到ZIP
            zipf.write(file_path, arcname=file.name + file.extension)

    # 重置缓冲区指针
    zip_buffer.seek(0)

    return zip_buffer


def get_file_path(url: str):
    static_dir = Path("static")  # 你的静态文件目录
    file_path = (static_dir / url).resolve()

    # 安全检查：确保文件在static目录内
    try:
        file_path.relative_to(static_dir.resolve())
    except ValueError:
        raise HTTPException(status_code=400, detail="文件路径无效")

    if not file_path.is_file():
        raise HTTPException(status_code=404, detail="找不到文件")
    return str(file_path)


def format_file_size(bytes_num):
    for unit in ["B", "KB", "MB", "GB"]:
        if bytes_num < 1024.0 or unit == "GB":
            break
        bytes_num /= 1024.0
    return f"{bytes_num:.2f} {unit}" if unit != "B" else f"{int(bytes_num)} B"


def get_file_md5(file: UploadFile) -> str:
    # 计算MD5
    md5_hash = hashlib.md5()
    for chunk in iter(lambda: file.file.read(4096), b""):
        md5_hash.update(chunk)
    md5 = md5_hash.hexdigest()
    # 重置文件指针
    file.file.seek(0)
    return md5
